#include "sdk.h"
#include <M_Code_debugger_interfaces.h>
#include "debugger_defs.h"
#include "debuggerdriver.h"
#include <wx/arrimpl.cpp>

const int DEBUGGER_CURSOR_CHANGED = wxNewId();
const int DEBUGGER_SHOW_FILE_LINE = wxNewId();

DebuggerCmd::DebuggerCmd( DebuggerDriver* driver, const wxString& cmd, bool logToNormalLog )
  : m_Cmd( cmd ),
    m_pDriver( driver ),
    m_LogToNormalLog( logToNormalLog ) {
}

void DebuggerCmd::ParseOutput( const wxString& output ) {
  if( !output.IsEmpty() && m_LogToNormalLog ) {
    m_pDriver->Log( output );
  }
}

DbgCmd_UpdateWatchesTree::DbgCmd_UpdateWatchesTree( DebuggerDriver* driver )
  : DebuggerCmd( driver ) {
}

void DbgCmd_UpdateWatchesTree::Action() {
  Manager::Get()->GetDebuggerManager()->GetWatchesDialog()->UpdateWatches();
}

class DebuggerInfoWindow : public wxScrollingDialog {
  public:
    DebuggerInfoWindow( wxWindow *parent, const wxString& title, const wxString& content )
      : wxScrollingDialog( parent, -1, title, wxDefaultPosition, wxDefaultSize,
                           wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX ) {
      wxSizer* sizer = new wxBoxSizer( wxVERTICAL );
      wxFont font( 8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL );
      m_pText = new wxTextCtrl( this, -1, content, wxDefaultPosition, wxDefaultSize,
                                wxTE_READONLY | wxTE_MULTILINE | wxTE_RICH2 | wxHSCROLL );
      m_pText->SetFont( font );
      sizer->Add( m_pText, 1, wxGROW );
      SetSizer( sizer );
      sizer->Layout();
    }
    wxTextCtrl* m_pText;
};

void DebuggerInfoCmd::ParseOutput( const wxString& output ) {
  DebuggerInfoWindow win( Manager::Get()->GetAppWindow(), m_Title, output );
  win.ShowModal();
}

void DebuggerBreakpoint::SetEnabled( bool flag ) {
  enabled = flag;
}

wxString DebuggerBreakpoint::GetLocation() const {
  switch( type ) {
    case bptData:
      return breakAddress;
    case bptCode:
      return filenameAsPassed;
    case bptFunction:
      return func;
    default:
      return _T( "Unknown" );
  }
}

int DebuggerBreakpoint::GetLine() const {
  return line;
}

wxString DebuggerBreakpoint::GetLineString() const {
  return ( type == bptCode ) ? F( _T( "%d" ), line ) : wxString( wxEmptyString );
}

wxString DebuggerBreakpoint::GetType() const {
  switch( type ) {
    case bptData:
      return _T( "Data" );
    case bptCode:
      return _T( "Code" );
    case bptFunction:
      return _T( "Function" );
    default:
      return _T( "Unknown" );
  }
}

wxString DebuggerBreakpoint::GetInfo() const {
  switch( type ) {
    case bptData:
      if( breakOnRead && breakOnWrite ) {
        return  _T( "type: read-write" );
      } else if( breakOnRead ) {
        return _T( "type: read" );
      } else if( breakOnWrite ) {
        return _T( "type: write" );
      } else
      { return _T( "type: unknown" ); }
    case bptCode: {
      wxString s;
      if( useCondition ) {
        s += _T( "condition: " ) + condition;
      }
      if( useIgnoreCount ) {
        if( !s.empty() ) {
          s += _T( " " );
        }
        s += F( _T( "ignore count: %d" ), ignoreCount );
      }
      if( temporary ) {
        if( !s.empty() ) {
          s += _T( " " );
        }
        s += _T( "temporary" );
      }
      s += F( _T( " (index: %ld)" ), index );
      return s;
    }
    case bptFunction:
    default:
      return wxEmptyString;
  }
}

bool DebuggerBreakpoint::IsEnabled() const {
  return enabled;
}

bool DebuggerBreakpoint::IsVisibleInEditor() const {
  return type == bptCode;
}

bool DebuggerBreakpoint::IsTemporary() const {
  return temporary;
}


GDBWatch::GDBWatch( wxString const &symbol ) :
  m_symbol( symbol ),
  m_format( Undefined ),
  m_array_start( 0 ),
  m_array_count( 0 ),
  m_is_array( false ),
  m_forTooltip( false ) {
}
GDBWatch::~GDBWatch() {
}

void GDBWatch::GetSymbol( wxString &symbol ) const {
  symbol = m_symbol;
}

void GDBWatch::GetValue( wxString &value ) const {
  value = m_raw_value;
}
bool GDBWatch::SetValue( const wxString &value ) {
  if( m_raw_value != value ) {
    MarkAsChanged( true );
    m_raw_value = value;
  }
  return true;
}

void GDBWatch::GetFullWatchString( wxString &full_watch ) const {
  cb::shared_ptr<const cbWatch> parent = GetParent();
  if( parent ) {
    parent->GetFullWatchString( full_watch );
    full_watch += _T( "." ) + m_symbol;
  } else {
    full_watch = m_symbol;
  }
}

void GDBWatch::GetType( wxString &type ) const {
  type = m_type;
}

void GDBWatch::SetType( const wxString &type ) {
  m_type = type;
}

wxString const & GDBWatch::GetDebugString() const {
  return m_debug_value;
}

wxString GDBWatch::MakeSymbolToAddress() const {
  return _T( "&" ) + m_symbol;
}

bool GDBWatch::IsPointerType() const {
  return ::IsPointerType( m_type );
}

void GDBWatch::SetDebugValue( wxString const &value ) {
  m_debug_value = value;
}

void GDBWatch::SetSymbol( const wxString& symbol ) {
  m_symbol = symbol;
}

void GDBWatch::DoDestroy() {
  delete this;
}

void GDBWatch::SetFormat( WatchFormat format ) {
  m_format = format;
}

WatchFormat GDBWatch::GetFormat() const {
  return m_format;
}

void GDBWatch::SetArray( bool flag ) {
  m_is_array = flag;
}

bool GDBWatch::IsArray() const {
  return m_is_array;
}

void GDBWatch::SetArrayParams( int start, int count ) {
  m_array_start = start;
  m_array_count = count;
}

int GDBWatch::GetArrayStart() const {
  return m_array_start;
}

int GDBWatch::GetArrayCount() const {
  return m_array_count;
}

void GDBWatch::SetForTooltip( bool flag ) {
  m_forTooltip = flag;
}

bool GDBWatch::GetForTooltip() const {
  return m_forTooltip;
}

bool IsPointerType( wxString type ) {
  type.Trim( true );
  type.Trim( false );
  if( type.Contains( _T( "char *" ) ) || type.Contains( _T( "char const *" ) ) ) {
    return false;
  } else if( type.EndsWith( _T( "*" ) ) ) {
    return true;
  } else if( type.EndsWith( _T( "* const" ) ) ) {
    return true;
  } else if( type.EndsWith( _T( "* volatile" ) ) ) {
    return true;
  }
  return false;
}

wxString CleanStringValue( wxString value ) {
  while( value.EndsWith( _T( "\\" ) ) ) {
    value.RemoveLast();
  }
  return value;
}

